#ifndef TOKEN_H
#define TOKEN_H
#include <string>

using std::string;

enum class TOKEN : int
{
    VAR_TOKEN = 0, // variables
    ASSIGN_TOKEN,  // =
    INT_TOKE,      // integer val
    ADD_TOKEN,     // +
    MINUS_TOKEN,   // -
    MUL_TOKEN,     // *
    DIV_TOKEN,     // /
    SEMI_TOKEN,    // ;
    END_TOKEN,     // end of file
    PRINT_TOKEN,   // print variable value
    UNKOWN,
};

class Token
{
public:
    Token() : token_(TOKEN::UNKOWN), token_name_("Unknown") {};
    Token(TOKEN token, string name) : token_(token), token_name_(name) {};
    virtual ~Token() = default;
    virtual string ToString()
    {
        return token_name_;
    }
    TOKEN GetTokenType()
    {
        return token_;
    }

protected:
    string token_name_;
    TOKEN token_;
};

class VarToken : public Token
{
public:
    VarToken() : Token(TOKEN::VAR_TOKEN, "VarToken") {};
    VarToken(string var_name) : Token(TOKEN::VAR_TOKEN, "VarToken"), var_name_(var_name) {};
    virtual ~VarToken() = default;
    string ToString() override
    {
        return var_name_;
    }
private:
    string var_name_;
};

class AssignToken : public Token
{
public:
    AssignToken() : Token(TOKEN::ASSIGN_TOKEN, "AssignToken") {};
    AssignToken(string var_name) : Token(TOKEN::ASSIGN_TOKEN, "AssignToken") {};
    virtual ~AssignToken() = default;
};

class IntToken : public Token
{
public:
    IntToken();
    IntToken(int val) : Token(TOKEN::INT_TOKE, "IntToken")
    {
        int_val_ = val;
    };
    virtual ~IntToken() = default;
    string ToString() override
    {
        ostringstream oss;
        oss << int_val_;
        return oss.str();
    }
private:
    int int_val_ = 0;
};

class AddToken : public Token
{
public:
    AddToken() : Token(TOKEN::ADD_TOKEN, "AddToken") {};
    virtual ~AddToken() = default;
};

class MinusToken : public Token
{
public:
    MinusToken() : Token(TOKEN::MINUS_TOKEN, "MinusToken") {};
    virtual ~MinusToken() = default;
};

class MulToken : public Token
{
public:
    MulToken() : Token(TOKEN::MUL_TOKEN, "MulToken") {};
    virtual ~MulToken() = default;
};

class DivToken : public Token
{
public:
    DivToken() : Token(TOKEN::DIV_TOKEN, "DivToken") {};
    virtual ~DivToken() = default;
};

class SemiToken : public Token
{
public:
    SemiToken() : Token(TOKEN::SEMI_TOKEN, "SemiToken") {};
    virtual ~SemiToken() = default;
};

class EndToken : public Token
{
public:
    EndToken() : Token(TOKEN::END_TOKEN, "EndToken") {};
    virtual ~EndToken() = default;
};

class PrintToken : public Token
{
public:
    PrintToken() : Token(TOKEN::PRINT_TOKEN, "PrintToken") {};
    virtual ~PrintToken() = default;
};

#endif // TOKEN_H